// ============================================
// 10 - 错误处理 (Error Handling)
// ============================================

/// Rust 将错误分为两类:
/// 1. 可恢复错误 (Result<T, E>)
/// 2. 不可恢复错误 (panic!)

use std::fs::File;
use std::io::{self, Read, ErrorKind};

// ==================== panic! 宏 ====================

/// 不可恢复错误
/// 当出现严重错误时，使用 panic! 宏终止程序
pub fn panic_basics() {
    println!("\n=== panic! 基础 ===");
    
    println!("panic! 会:");
    println!("1. 打印错误信息");
    println!("2. 展开和清理栈数据");
    println!("3. 退出程序");
    
    // panic!("崩溃了！"); // 这会终止程序
    
    println!("示例: panic!(\"出现严重错误\");");
}

/// 使用 panic! 的 backtrace
pub fn panic_backtrace() {
    println!("\n=== panic! 回溯 ===");
    
    println!("设置环境变量查看详细回溯:");
    println!("RUST_BACKTRACE=1 cargo run");
    println!("RUST_BACKTRACE=full cargo run");
    
    // 示例: 数组越界会触发 panic
    // let v = vec![1, 2, 3];
    // v[99]; // panic!
}

// ==================== Result 枚举 ====================

/// Result 枚举用于可恢复错误
/// enum Result<T, E> {
///     Ok(T),
///     Err(E),
/// }
pub fn result_basics() {
    println!("\n=== Result 基础 ===");
    
    // 尝试打开文件
    let greeting_file_result = File::open("hello.txt");
    
    match greeting_file_result {
        Ok(file) => println!("文件打开成功: {:?}", file),
        Err(error) => println!("打开文件出错: {:?}", error),
    }
}

/// 匹配不同的错误
pub fn matching_different_errors() {
    println!("\n=== 匹配不同错误 ===");
    
    let greeting_file_result = File::open("hello.txt");
    
    let _greeting_file = match greeting_file_result {
        Ok(file) => file,
        Err(error) => match error.kind() {
            ErrorKind::NotFound => match File::create("hello.txt") {
                Ok(fc) => {
                    println!("文件不存在，创建新文件");
                    fc
                }
                Err(e) => panic!("创建文件失败: {:?}", e),
            },
            other_error => {
                panic!("打开文件时出错: {:?}", other_error);
            }
        },
    };
}

/// 使用闭包简化错误处理
pub fn unwrap_or_else() {
    println!("\n=== unwrap_or_else ===");
    
    let _greeting_file = File::open("hello.txt").unwrap_or_else(|error| {
        if error.kind() == ErrorKind::NotFound {
            File::create("hello.txt").unwrap_or_else(|error| {
                panic!("创建文件失败: {:?}", error);
            })
        } else {
            panic!("打开文件时出错: {:?}", error);
        }
    });
}

/// unwrap 和 expect
pub fn unwrap_and_expect() {
    println!("\n=== unwrap 和 expect ===");
    
    // unwrap: 如果是 Ok，返回值；如果是 Err，panic!
    // let file = File::open("hello.txt").unwrap();
    
    // expect: 类似 unwrap，但可以指定错误信息
    // let file = File::open("hello.txt")
    //     .expect("无法打开 hello.txt");
    
    println!("unwrap: 简单但会 panic");
    println!("expect: 可以提供更好的错误信息");
}

// ==================== 传播错误 ====================

/// 传播错误
/// 将错误返回给调用者处理
pub fn propagating_errors() {
    println!("\n=== 传播错误 ===");
    
    match read_username_from_file() {
        Ok(username) => println!("用户名: {}", username),
        Err(e) => println!("读取失败: {:?}", e),
    }
}

fn read_username_from_file() -> Result<String, io::Error> {
    let username_file_result = File::open("username.txt");
    
    let mut username_file = match username_file_result {
        Ok(file) => file,
        Err(e) => return Err(e), // 传播错误
    };
    
    let mut username = String::new();
    
    match username_file.read_to_string(&mut username) {
        Ok(_) => Ok(username),
        Err(e) => Err(e), // 传播错误
    }
}

/// ? 运算符
/// 简化错误传播
pub fn question_mark_operator() {
    println!("\n=== ? 运算符 ===");
    
    fn read_username() -> Result<String, io::Error> {
        let mut username_file = File::open("username.txt")?; // ? 会传播错误
        let mut username = String::new();
        username_file.read_to_string(&mut username)?;
        Ok(username)
    }
    
    // 更简洁的写法
    fn read_username_short() -> Result<String, io::Error> {
        let mut username = String::new();
        File::open("username.txt")?.read_to_string(&mut username)?;
        Ok(username)
    }
    
    // 链式调用
    fn read_username_chain() -> Result<String, io::Error> {
        std::fs::read_to_string("username.txt")
    }
    
    match read_username() {
        Ok(name) => println!("用户名: {}", name),
        Err(e) => println!("读取失败: {:?}", e),
    }
    
    let _ = read_username_short();
    let _ = read_username_chain();
}

/// ? 运算符的工作原理
pub fn how_question_mark_works() {
    println!("\n=== ? 运算符工作原理 ===");
    
    println!("? 运算符:");
    println!("1. 如果值是 Ok，返回 Ok 中的值");
    println!("2. 如果值是 Err，将错误返回给调用者");
    println!("3. 自动进行类型转换 (使用 From trait)");
}

/// ? 运算符可以用于 Option
pub fn question_mark_with_option() {
    println!("\n=== ? 用于 Option ===");
    
    fn last_char_of_first_line(text: &str) -> Option<char> {
        text.lines().next()?.chars().last()
    }
    
    let result = last_char_of_first_line("Hello\nWorld");
    println!("最后一个字符: {:?}", result);
    
    let empty = last_char_of_first_line("");
    println!("空字符串: {:?}", empty);
}

/// main 函数返回 Result
pub fn main_with_result() {
    println!("\n=== main 返回 Result ===");
    
    println!("main 函数可以返回 Result:");
    println!("fn main() -> Result<(), Box<dyn Error>> {{");
    println!("    let f = File::open(\"hello.txt\")?;");
    println!("    Ok(())");
    println!("}}");
}

// ==================== 何时使用 panic! ====================

/// 何时使用 panic!
pub fn when_to_panic() {
    println!("\n=== 何时使用 panic! ===");
    
    println!("应该使用 panic! 的情况:");
    println!("1. 示例、原型代码和测试");
    println!("2. 你比编译器知道更多信息");
    println!("3. 代码进入了无效状态");
    println!("4. 错误是不可恢复的");
    
    println!("\n应该返回 Result 的情况:");
    println!("1. 错误是预期的");
    println!("2. 调用者可以决定如何处理");
    println!("3. 失败是一种可能的结果");
}

/// 在原型代码中使用 unwrap
pub fn prototyping() {
    println!("\n=== 原型代码 ===");
    
    println!("在原型代码中，可以使用 unwrap 或 expect");
    println!("这样可以快速开发，之后再添加错误处理");
}

/// 有更多信息时
pub fn when_you_have_more_info() {
    println!("\n=== 有更多信息时 ===");
    
    use std::net::IpAddr;
    
    // 硬编码的 IP 地址，我们知道它有效
    let home: IpAddr = "127.0.0.1"
        .parse()
        .expect("硬编码的 IP 地址应该有效");
    
    println!("IP 地址: {}", home);
}

// ==================== 自定义错误类型 ====================

/// 创建自定义错误类型
pub fn custom_error_types() {
    println!("\n=== 自定义错误类型 ===");
    
    use std::fmt;
    
    #[derive(Debug)]
    struct CustomError {
        details: String,
    }
    
    impl CustomError {
        fn new(msg: &str) -> CustomError {
            CustomError {
                details: msg.to_string(),
            }
        }
    }
    
    impl fmt::Display for CustomError {
        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
            write!(f, "{}", self.details)
        }
    }
    
    impl std::error::Error for CustomError {}
    
    fn do_something() -> Result<(), CustomError> {
        Err(CustomError::new("出现了问题"))
    }
    
    match do_something() {
        Ok(_) => println!("成功"),
        Err(e) => println!("错误: {}", e),
    }
}

// ==================== 使用 thiserror 和 anyhow ====================

/// 错误处理库
pub fn error_handling_crates() {
    println!("\n=== 错误处理库 ===");
    
    println!("推荐的错误处理库:");
    println!("1. thiserror: 简化自定义错误类型");
    println!("   - 派生 Error trait");
    println!("   - 自动实现 Display");
    println!("");
    println!("2. anyhow: 简化应用程序错误处理");
    println!("   - 提供 Result<T> 别名");
    println!("   - 提供上下文信息");
    println!("   - 简化错误链");
}

// ==================== 实际应用示例 ====================

/// 配置读取示例
pub fn practical_example() {
    println!("\n=== 实际应用: 配置读取 ===");
    
    #[derive(Debug)]
    struct Config {
        filename: String,
        max_size: u32,
    }
    
    impl Config {
        fn new(args: &[String]) -> Result<Config, &'static str> {
            if args.len() < 3 {
                return Err("参数不足");
            }
            
            let filename = args[1].clone();
            let max_size = args[2]
                .parse()
                .map_err(|_| "max_size 必须是数字")?;
            
            Ok(Config { filename, max_size })
        }
    }
    
    let args = vec![
        String::from("program"),
        String::from("config.txt"),
        String::from("1024"),
    ];
    
    match Config::new(&args) {
        Ok(config) => println!("配置: {:?}", config),
        Err(e) => println!("错误: {}", e),
    }
}

/// 多种错误类型
pub fn multiple_error_types() {
    println!("\n=== 处理多种错误类型 ===");
    
    use std::num::ParseIntError;
    
    #[derive(Debug)]
    enum MyError {
        Io(io::Error),
        Parse(ParseIntError),
    }
    
    impl From<io::Error> for MyError {
        fn from(err: io::Error) -> MyError {
            MyError::Io(err)
        }
    }
    
    impl From<ParseIntError> for MyError {
        fn from(err: ParseIntError) -> MyError {
            MyError::Parse(err)
        }
    }
    
    fn read_number() -> Result<i32, MyError> {
        let s = std::fs::read_to_string("number.txt")?;
        let n: i32 = s.trim().parse()?;
        Ok(n)
    }
    
    match read_number() {
        Ok(n) => println!("数字: {}", n),
        Err(e) => println!("错误: {:?}", e),
    }
}

/// 错误处理最佳实践
pub fn best_practices() {
    println!("\n=== 错误处理最佳实践 ===");
    
    println!("1. 优先使用 Result 而不是 panic!");
    println!("2. 使用 ? 运算符简化错误传播");
    println!("3. 提供有意义的错误信息");
    println!("4. 使用 expect 而不是 unwrap");
    println!("5. 考虑使用 thiserror 和 anyhow");
    println!("6. 在库代码中返回 Result");
    println!("7. 在应用代码中可以使用 panic!");
    println!("8. 为自定义错误实现 Error trait");
}

/// 主函数 - 演示所有功能
#[allow(dead_code)]
pub fn main() {
    println!("╔════════════════════════════════════════╗");
    println!("║   Rust 错误处理教程                    ║");
    println!("╚════════════════════════════════════════╝");
    
    panic_basics();
    panic_backtrace();
    result_basics();
    matching_different_errors();
    unwrap_or_else();
    unwrap_and_expect();
    propagating_errors();
    question_mark_operator();
    how_question_mark_works();
    question_mark_with_option();
    main_with_result();
    when_to_panic();
    prototyping();
    when_you_have_more_info();
    custom_error_types();
    error_handling_crates();
    practical_example();
    multiple_error_types();
    best_practices();
    
    println!("\n✅ 错误处理教程完成！");
}

#[cfg(test)]
mod tests {
    use super::*;
    
    #[test]
    fn test_result_ok() {
        let result: Result<i32, &str> = Ok(42);
        assert!(result.is_ok());
        assert_eq!(result.unwrap(), 42);
    }
    
    #[test]
    fn test_result_err() {
        let result: Result<i32, &str> = Err("error");
        assert!(result.is_err());
    }
    
    #[test]
    fn test_unwrap_or() {
        let ok_value: Result<i32, &str> = Ok(42);
        let err_value: Result<i32, &str> = Err("error");
        
        assert_eq!(ok_value.unwrap_or(0), 42);
        assert_eq!(err_value.unwrap_or(0), 0);
    }
}

